Building an Interactive Shiny App: Exploring World Health Organization’s Global HIV-1 Incidence Data (1990-2021)
Introduction
In the fight against HIV/AIDS, data analysis and visualization play a crucial role in understanding the global epidemic, identifying trends, and informing policy decisions. This blog aims to walk you through a step-by-step process for building an interactive Shiny app using the World Health Organization’s (WHO) global HIV-1 incidence data from 1990 to 2021. Using the power of R and Shiny, dynamic visualizations can be generated that allows users to explore and analyze the changing patterns of HIV-1 incidence over time.
Steps to building the web application
Step 1. Data Acquisition and Preparation
HIV incidence data was download from the World Health Organization data repository. The dataset contained estimates for HIV prevalence, AIDS-related deaths, new HIV infections for all countries from 1990 to 2021.
The data was downloaded as an excel file for the data repository. The imported excel file had multiple merged cells. The columns with country names, HIV-1 incidence estimates and years were extracted to a new sheet and saved as a csv file.
Step 2: Data cleaning and preparation
The csv file was imported into Rstudio and the data was grouped by country. To map the data, longitude and latitude coordinate data for each country was added to the dataset.
Step 3: Setting up the Shiny Environment and creating the app
To create the shiny app, a new file type for shiny web app was created and saved in a separate folder within the working environment.
To create the shiny app; 3 components were needed
- User interface (UI) which represents the front end of the app which the end user sees and interact with.
- Server which represent the backend of the shiny app which computes the required outputs based on the input given by the end user.
- The shiny interface which bridges the ui and server.
In this example, the UI was made of a sidebar and main panel. The main panel had 2 tabs. The first tab shows an interactive map and with a slider for years ranging from 1990 t0 2021. Moving the slider across the year range by one level results in the map adjusting to reflect the HIV-incidence for that year. The second tab showed a graph for HIV-1 incidence from 1990 to 2021 with a drop down menu for selecting country. Selecting a country from the drop down menu resulted in the graph adjusting to reflect HIV-incidence for that country.
For data to be correctly filtered when a user of the shiny web app slides the slider or the user selects a country from the drop-down menu, the data imputed to the server had to be converted to a reactive object. This was then used to create two reactive apps. The first app being a reactive leaflet map which filtered HIV-1 incidence based on the year selected. HIV-1 incidence estimates is presented as a blue circle super-imposed onto the country. The second reactive app is a reactive ggplot graph which is filtered based on the country selected by the user from the drop down menu.
The complete code for this shiny app is as shown below
# install and load packages
library(maps)
library(utils)
library(shiny) ## package for interactive app
library(leaflet) ## package for map
library(ggplot2) ## package for generating graph
library(dplyr) ## package for merging, grouping and filtering data
library(ggmap) ## package for adding longitudinal and latitudinal coordinates
library(bslib) ## package for theming shiny ui
library(thematic) # package for theming shiny ggplot
# import HIV data
hiv_data <- read.csv("ExcelFileInCSVformat.csv")
# manipulate data using dplyr
hiv_data <- hiv_data %>%
group_by(country)
# Generate dataset with longitudes and latititudes for each country of the world
world_map <- map_data("world")
# Add latitudes and longitudes to hiv_data
hiv_mapped_data <- merge(world_map, hiv_data, by.x = "region", by.y = "country")
# filter out rows that do not have HIV incidence estimates
hiv_map_data1 <- hiv_map_data %>% filter(!is.na(hiv_map_data$incidence))
hiv_map_data1 <- hiv_map_data1 %>%
group_by(region)
# create shiny app
thematic::thematic_shiny() ## This code adds the ui theme to ggplot
## UI for shiny app
ui <- fluidPage(theme = bs_theme(
bg = "#B8BCC2",
fg = "#34373a",
primary = "blue",
secondary = "red",
base_font = font_google("Roboto Condensed")),
sidebarLayout(sidebarPanel(titlePanel((strong("HIV Incidence"))), br(), em("HIV incidence data for all ages from 1990 to 2021 based on Joint United Nations Programme on HIV/AIDS (UNAIDS)"), h5("Data source:"), h5(a(href="https://aidsinfo.unaids.org/", "Data Repository")), width = 3),
mainPanel(
tabsetPanel(
tabPanel(h5(strong("HIV incidence per year")), p(" "), sliderInput("year", strong("Select year:"), min = 1990, max = 2021, value = 1995, step = 1, sep = "", width = "100%"), leafletOutput("map", width = "100%", height = "375px")),
tabPanel(h5(strong("HIV incidence per country")), br(), selectInput("country", strong("Select a country:"), choices = sort(unique(hiv_data$country))), plotOutput("plot2", width = "100%", height = "400px"))
)
)
))
## Server for shiny app
server <- function(input, output, session) {
## reactive data filtered by selected year
filtered_data <- reactive({
hiv_data %>% filter(year == input$year)
})
filtered_data2 <- reactive({
hiv_map_data1 %>% filter(region == input$region)
})
## create map
output$map <- renderLeaflet({
leaflet(options = leafletOptions(minZoom = 1.7, width = "500px", height = "700px"))%>%
addTiles() %>%
fitBounds(lng1 = 160, lat1 = -180, lng2 = -100, lat2 = 180) %>%
setMaxBounds(lng1 = 160, lat1 = -180, lng2 = -100, lat2 = 180) %>%
setView(lng = 40, lat = 0, zoom = 2) %>%
addProviderTiles("OpenStreetMap") %>%
setMaxBounds(lng1 = min(hiv_data$longitude),
lat1 = min(hiv_data$latitude),
lng2 = max(hiv_data$longitude),
lat2 = max(hiv_data$longitude)) %>%
#setView(0,0,2) %>%
addProviderTiles(providers$CartoDB.Positron) %>%
clearBounds() %>%
addCircleMarkers(data = filtered_data(), ~longitude, ~latitude, label = ~paste0(country, sep =" ", incidence), radius = ~incidence*2, color = "blue", fillOpacity = 0.4, stroke= FALSE, )
})
## create graph
output$plot2 <- renderPlot({
ggplot(data = hiv_data[hiv_data$country == input$country,], aes(x = year, y = incidence)) +
geom_line() +
ggtitle(paste("HIV incidence for", input$country)) +
labs(x = "Years", y = "HIV incidence (per 1000 uninfected populations)") + theme(text=element_text(size=15), axis.title=element_text(size=15), plot.title=element_text(size=20))
}
)
}
# run shiny app
shinyApp(ui = ui, server = server)
Step 4: Deploying and Sharing the Shiny
The app was then uploaded to my shinyapp.io server account for easy sharing of the app.
Conclusion
This step-by-step guide shows how RShiny can be harnessed to create interactive data visualizations. This Shiny app will enable users to explore and analyze the changing patterns of HIV-1 incidence over the past three decades. By democratizing access to this valuable data, researchers and policymakers can gain deeper insights, identify trends, and make informed decisions in the ongoing battle against HIV/AIDS.
Please check out my other blogs. I greatly appreciate any feedbacks and comments and please subscribe to be updated on my latest blogs.
Please share your thoughts, interests and questions in the comments below or on the upper right side of the page.
Feel free to share this page on your preferred social media platforms using the sharing options conveniently located on this page.
Citations
- Bivand, R.S., Pebesma, E. and Gomez-Rubio, V. (2013) Applied spatial data analysis with R, Second edition. Springer, NY. Available at: https://asdar-book.org/.
- Brownrigg, R. (2022) maps: Draw geographical maps. manual. Available at: https://CRAN.R-project.org/package=maps.
- Chang, W. et al. (2022) shiny: Web application framework for R. manual. Available at: https://shiny.rstudio.com/.
- Kahle, D., Wickham, H. and Jackson, S. (2023) ggmap: Spatial Visualization with ggplot2. manual. Available at: https://github.com/dkahle/ggmap.
- Pebesma, E. and Bivand, R. (2023) sp: Classes and methods for spatial data. manual. Available at: https://CRAN.R-project.org/package=sp.
- R Core Team (2022) R: A language and environment for statistical computing. manual. Vienna, Austria: R Foundation for Statistical Computing. Available at: https://www.R-project.org/.
- Sievert, C., Cheng, J. and Aden-Buie, G. (2023) bslib: Custom Bootstrap ‘Sass’ Themes for shiny and rmarkdown. manual. Available at: https://CRAN.R-project.org/package=bslib.
- Sievert, C., Schloerke, B. and Cheng, J. (2021) thematic: Unified and Automatic Theming of ggplot2, lattice, and base R Graphics. manual. Available at: https://CRAN.R-project.org/package=thematic.
- Wickham, H. (2016) ggplot2: Elegant graphics for data analysis. Springer-Verlag New York. Available at: https://ggplot2.tidyverse.org.
- Wickham, H. et al. (2022) dplyr: A grammar of data manipulation. manual. Available at: https://CRAN.R-project.org/package=dplyr.
- Wickham, H. (2020)Mastering Shiny. Available at: https://mastering-shiny.org/ (Accessed: 9 May 2023).